﻿using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;

using Vestras.StarCraft2.Luna.Parser;
using Vestras.StarCraft2.Luna.Parser.Ast;

namespace Vestras.StarCraft2.Luna.Validation {
    public static class ExpressionExtensionMethods {
        public static bool IsNull(this Expression expression) {
            if (expression is IdentifierExpression) {
                return ((IdentifierExpression)expression).Identifier == "null";
            }

            return false;
        }

        static List<string> processedFileNames = new List<string>();
        private static string _GetProperIncludeString(this string includeString, string includingFile) {
            processedFileNames.Add(includingFile);
            includeString = includeString.Replace("\"", "");
            includeString = includeString.Replace("/", "\\");
            string includeStringDirectory = Path.GetDirectoryName(includeString);
            string startDirectory = includeStringDirectory;
            string directoryName = Path.GetDirectoryName(includingFile);
            while (!string.IsNullOrEmpty(includeStringDirectory)) {
                if (directoryName.EndsWith(includeStringDirectory)) {
                    directoryName = directoryName.Substring(0, directoryName.Length - startDirectory.Length - (startDirectory.Length == 0 ? 0 : 1)); // 1 = length of "\\"
                    break;
                }

                int index = includeStringDirectory.IndexOf("\\");
                if (index > -1) {
                    string oldDirectory = includeStringDirectory;
                    string toAdd = includeStringDirectory.Substring(index, includeStringDirectory.Length - index);
                    includeStringDirectory = includeStringDirectory.Substring(0, index);
                    includeString = toAdd.Replace("\\", "") + "\\" + includeString.Replace(oldDirectory, "").Replace("\\", "");
                    startDirectory = "";
                } else {
                    break;
                }
            }

            string fileName = directoryName + "\\" + includeString;
            if (!File.Exists(fileName)) {
                foreach (string entityFileName in FileNetworkParser.CurrentlyIncludedFiles) {
                    if (!processedFileNames.Contains(entityFileName) && File.Exists(entityFileName)) {
                        string tryFileName = includeString._GetProperIncludeString(entityFileName);
                        if (File.Exists(tryFileName)) {
                            return tryFileName;
                        }
                    }
                }
            }

            return fileName;
        }

        public static string GetProperIncludeString(this string includeString, string includingFile) {
            processedFileNames.Clear();
            return _GetProperIncludeString(includeString, includingFile);
        }

        public static bool IsIncludedByFile(this string testString, string includingFile) {
            foreach (var pair in NamedEntityRegistre.Entities) {
                foreach (Entity entity in pair.Value) {
                    if (entity.FileName == includingFile && entity is Include) {
                        string properIncludeString = ((Include)entity).IncludedPath.GetProperIncludeString(includingFile);
                        if (properIncludeString == testString || testString.IsIncludedByFile(properIncludeString)) {
                            return true;
                        }
                    }
                }
            }

            return false;
        }

        private static void FixTypes(ref string leftType, ref string rightType) {
            if (leftType == "null") {
                leftType = rightType;
            }

            if (rightType == "null") {
                rightType = leftType;
            }

            if ((leftType == "int" || leftType == "byte") && (rightType == "int" || rightType == "byte")) {
                leftType = "int";
                rightType = "int";
            }

            if ((leftType == "fixed" && rightType != "fixed") || (leftType != "fixed" && rightType == "fixed")) {
                leftType = "fixed";
                rightType = "fixed";
            }
        }

        public static bool DoesTypeReferenceResolveToTypedefCreatedType(this TypeReference typeReference, string typedefCreatedTypeId) {
            IList<Entity> list = new List<Entity>(ScopeEntityFilterer.FilterEntities(NamedEntityRegistre.GetEntitiesWithName(typedefCreatedTypeId), typeReference));
            if (list == null) {
                return false;
            }

            List<Entity> entitiesToRemove = new List<Entity>();
            foreach (Entity entity in list) {
                if (!(entity is Typedef)) {
                    entitiesToRemove.Add(entity);
                }
            }

            entitiesToRemove.ForEach(item => list.Remove(item));
            if (list.Count == 0) {
                return false;
            }

            Typedef typedef = list[0] as Typedef;
            if (typedef == null) {
                return false;
            }

            if (typedef.OriginalType.Type.GetQualifiedId() == typeReference.Type.GetQualifiedId()) {
                if (typedef.OriginalType.ArrayDimensionExpressions.Count != typeReference.ArrayDimensionExpressions.Count) {
                    return false;
                }

                bool arrayDimensionsValid = true;
                for (int i = 0; i < typeReference.ArrayDimensionExpressions.Count; i++) {
                    ValueExpression originalExpression = typedef.OriginalType.ArrayDimensionExpressions[i] as ValueExpression;
                    ValueExpression typeReferenceExpression = typeReference.ArrayDimensionExpressions[i] as ValueExpression;
                    int originalDimension;
                    int typeReferenceDimension;
                    if (int.TryParse(originalExpression.Value.GetQualifiedId(), out originalDimension) && int.TryParse(typeReferenceExpression.Value.GetQualifiedId(), out typeReferenceDimension)) {
                        if (originalDimension != typeReferenceDimension) {
                            arrayDimensionsValid = false;
                            break;
                        }
                    }
                }

                if (arrayDimensionsValid) {
                    return true;
                }
            }

            return false;
        }

        public static bool DoesExpressionResolveToType(this Expression expression, TypeReference typeReference) {
            string typeId = typeReference.GetTypeQualifiedId();
            if (expression is IdentifierExpression) {
                IdentifierExpression identifierExpression = expression as IdentifierExpression;
                if ((identifierExpression.Identifier == "true" || identifierExpression.Identifier == "false") && typeId == "bool") {
                    return true;
                }

                IList<Entity> list = new List<Entity>(ScopeEntityFilterer.FilterEntities(NamedEntityRegistre.GetEntitiesWithName(identifierExpression.Identifier), expression));
                if (list == null || list.Count == 0) {
                    return false;
                }

                string ambiguityEntities;
                if (list.IsAmbiguous(out ambiguityEntities)) {
                    ErrorSink.AddError(ErrorSink.Error.Create("Ambiguity between entities " + ambiguityEntities, identifierExpression));
                }

                Entity entity = list[0];
                if (entity is Variable) {
                    string entityTypeId = ((Variable)entity).Type.GetQualifiedId();
                    return entityTypeId == typeId || (new TypeReference(new IdentifierExpression(entityTypeId))).DoesTypeReferenceResolveToTypedefCreatedType(typeId) || (new TypeReference(new IdentifierExpression(typeId))).DoesTypeReferenceResolveToTypedefCreatedType(entityTypeId) || (entityTypeId == "int" && typeId == "fixed") || (entityTypeId == "fixed" && typeId == "int");
                } else if (entity is Function) {
                    string entityTypeId = ((Variable)entity).Type.GetQualifiedId();
                    return entityTypeId == typeId || (new TypeReference(new IdentifierExpression(entityTypeId))).DoesTypeReferenceResolveToTypedefCreatedType(typeId) || (new TypeReference(new IdentifierExpression(typeId))).DoesTypeReferenceResolveToTypedefCreatedType(entityTypeId) || (entityTypeId == "int" && typeId == "fixed") || (entityTypeId == "fixed" && typeId == "int");
                } else if (entity is Struct) {
                    return ((Struct)entity).Name == typeId || (new TypeReference(new IdentifierExpression(((Struct)entity).Name))).DoesTypeReferenceResolveToTypedefCreatedType(typeId) || (new TypeReference(new IdentifierExpression(typeId)).DoesTypeReferenceResolveToTypedefCreatedType(((Struct)entity).Name));
                } else if (entity is Typedef) {
                    return ((Typedef)entity).CreatedType.GetQualifiedId() == typeId || (new TypeReference(new IdentifierExpression(((Typedef)entity).CreatedType.GetQualifiedId()))).DoesTypeReferenceResolveToTypedefCreatedType(typeId) || (new TypeReference(new IdentifierExpression(typeId))).DoesTypeReferenceResolveToTypedefCreatedType(((Typedef)entity).CreatedType.GetQualifiedId());
                }
            } else if (expression is ValueExpression) {
                ValueExpression valueExpression = expression as ValueExpression;
                switch (valueExpression.Type) {
                    case ValueExpression.ExpressionType.FloatLiteral:
                        return typeId == "fixed" || (new TypeReference(new IdentifierExpression("fixed"))).DoesTypeReferenceResolveToTypedefCreatedType(typeId);
                    case ValueExpression.ExpressionType.HexLiteral:
                    case ValueExpression.ExpressionType.OctLiteral:
                    case ValueExpression.ExpressionType.DecLiteral:
                        return typeId == "fixed" || typeId == "int" || (new TypeReference(new IdentifierExpression("int"))).DoesTypeReferenceResolveToTypedefCreatedType(typeId) || (new TypeReference(new IdentifierExpression("fixed"))).DoesTypeReferenceResolveToTypedefCreatedType(typeId);
                    case ValueExpression.ExpressionType.StringLiteral:
                        return typeId == "string" || (new TypeReference(new IdentifierExpression("string"))).DoesTypeReferenceResolveToTypedefCreatedType(typeId);
                    case ValueExpression.ExpressionType.ExpressionEncapsulation:
                        return valueExpression.ChildExpression.DoesExpressionResolveToType((typeReference));
                    case ValueExpression.ExpressionType.MemberAccess:
                        return valueExpression.Value.DoesExpressionResolveToType(typeReference);
                }
            } else if (expression is MemberAccessExpression) {
                MemberAccessExpression memberAccessExpression = expression as MemberAccessExpression;
                IList<Entity> referencedEntities = new List<Entity>(memberAccessExpression.GetReferencedEntities());
                if (referencedEntities.Count == 0) {
                    ErrorSink.AddError(ErrorSink.Error.Create("Cannot find entity with name '" + memberAccessExpression.GetQualifiedId() + "'", memberAccessExpression));
                    return false;
                }

                string ambiguityEntities;
                if (referencedEntities.IsAmbiguous(out ambiguityEntities)) {
                    ErrorSink.AddError(ErrorSink.Error.Create("Ambiguity between entities " + ambiguityEntities, memberAccessExpression));
                }

                switch (memberAccessExpression.Type) {
                    case MemberAccessExpression.ExpressionType.ArrayAccess:
                    case MemberAccessExpression.ExpressionType.VariableAccess:
                        Variable variable = referencedEntities[0] as Variable;
                        if (variable != null) {
                            string entityTypeId = variable.Type.GetTypeQualifiedId();
                            return entityTypeId == typeId || (entityTypeId == "fixed" && typeId == "int") || (entityTypeId == "int" && typeId == "fixed") || variable.Type.DoesTypeReferenceResolveToTypedefCreatedType(typeId);
                        }

                        break;
                    case MemberAccessExpression.ExpressionType.FunctionCall:
                        Function function = referencedEntities[0] as Function;
                        if (function != null) {
                            string entityTypeId = function.Type.GetTypeQualifiedId();
                            return entityTypeId == typeId || (entityTypeId == "fixed" && typeId == "int") || (entityTypeId == "int" && typeId == "fixed") || function.Type.DoesTypeReferenceResolveToTypedefCreatedType(typeId);
                        }

                        break;
                }
            } else if (expression is UnaryExpression) {
                return ((UnaryExpression)expression).Value.DoesExpressionResolveToType(typeReference);
            } else if (expression is AddExpression) {
                AddExpression addExpression = expression as AddExpression;
                string leftType = addExpression.Left.GetTypeQualifiedId();
                string rightType = addExpression.Right.GetTypeQualifiedId();
                FixTypes(ref leftType, ref rightType);
                return leftType == rightType;
            } else if (expression is AssignExpression) {
                AssignExpression assignExpression = expression as AssignExpression;
                string leftType = assignExpression.Left.GetTypeQualifiedId();
                string rightType = assignExpression.Right.GetTypeQualifiedId();
                FixTypes(ref leftType, ref rightType);
                return leftType == rightType;
            } else if (expression is CompareExpression) {
                CompareExpression compareExpression = expression as CompareExpression;
                string leftType = compareExpression.Left.GetTypeQualifiedId();
                string rightType = compareExpression.Right.GetTypeQualifiedId();
                FixTypes(ref leftType, ref rightType);
                return leftType == rightType;
            } else if (expression is ConditionExpression) {
                ConditionExpression conditionExpression = expression as ConditionExpression;
                string leftType = conditionExpression.Left.GetTypeQualifiedId();
                string rightType = conditionExpression.Right.GetTypeQualifiedId();
                FixTypes(ref leftType, ref rightType);
                return leftType == rightType;
            } else if (expression is EquateExpression) {
                EquateExpression equateExpression = expression as EquateExpression;
                string leftType = equateExpression.Left.GetTypeQualifiedId();
                string rightType = equateExpression.Right.GetTypeQualifiedId();
                FixTypes(ref leftType, ref rightType);
                return leftType == rightType;
            } else if (expression is MultiplyExpression) {
                MultiplyExpression multiplyExpression = expression as MultiplyExpression;
                string leftType = multiplyExpression.Left.GetTypeQualifiedId();
                string rightType = multiplyExpression.Right.GetTypeQualifiedId();
                FixTypes(ref leftType, ref rightType);
                return leftType == rightType;
            } else if (expression is PointerExpression) {
                PointerExpression pointerExpression = expression as PointerExpression;
                string pointerExpressionTypeId = pointerExpression.GetTypeQualifiedId();
                return pointerExpressionTypeId == typeId || (pointerExpressionTypeId == "fixed" && typeId == "int") || (pointerExpressionTypeId == "int" && typeId == "fixed") || DoesTypeReferenceResolveToTypedefCreatedType(typeReference, pointerExpressionTypeId);
            } else if (expression is ShiftExpression) {
                ShiftExpression shiftExpression = expression as ShiftExpression;
                string leftType = shiftExpression.Left.GetTypeQualifiedId();
                string rightType = shiftExpression.Right.GetTypeQualifiedId();
                FixTypes(ref leftType, ref rightType);
                return leftType == rightType;
            }

            return false;
        }

        public static IEnumerable<Entity> GetReferencedEntities(this MemberAccessExpression expression) {
            string qualifiedId = expression.Member.GetQualifiedId();
            IEnumerable<Entity> list = ScopeEntityFilterer.FilterEntities(NamedEntityRegistre.GetEntitiesWithName(qualifiedId), expression);
            if (list == null) {
                return new List<Entity>();
            }

            return list;
        }

        public static IEnumerable<Entity> GetReferencedEntities(this IdentifierExpression expression) {
            IEnumerable<Entity> list = ScopeEntityFilterer.FilterEntities(NamedEntityRegistre.GetEntitiesWithName(expression.Identifier), expression);
            if (list == null) {
                return new List<Entity>();
            }

            return list;
        }

        public static IEnumerable<Entity> GetReferencedEntities(this PointerExpression pointerExpression) {
            string leftType = pointerExpression.Left.GetTypeQualifiedId();
            string rightType = pointerExpression.Right.GetQualifiedId();
            IList<Entity> structs = new List<Entity>(ScopeEntityFilterer.FilterEntities(NamedEntityRegistre.GetEntitiesWithName(leftType), pointerExpression));
            string ambiguityEntities;
            if (structs.IsAmbiguous(out ambiguityEntities)) {
                ErrorSink.AddError(ErrorSink.Error.Create("Ambiguity between entities " + ambiguityEntities, pointerExpression));
                return new List<Entity>();
            }

            Struct s = structs.Count > 0 ? structs[0] as Struct : null;
            if (s != null) {
                IEnumerable<Entity> list = NamedEntityRegistre.GetEntitiesWithName(rightType);
                if (list == null) {
                    ErrorSink.AddError(ErrorSink.Error.Create("Cannot find entity with name '" + rightType + "' in struct '" + s.Name + "'", pointerExpression));
                    return new List<Entity>();
                }

                IList<Entity> resultList = new List<Entity>();
                foreach (Entity entity in list) {
                    if (entity.Parent == s) {
                        resultList.Add(entity);
                    }
                }

                return resultList;
            }

            return new List<Entity>();
        }

        public static IEnumerable<Entity> GetReferencedTypes(this TypeReference typeReference) {
            string qualifiedId = typeReference.Type.GetQualifiedId();
            IList<Entity> list = new List<Entity>(ScopeEntityFilterer.FilterEntities(NamedEntityRegistre.GetEntitiesWithName(qualifiedId), typeReference));
            if (list == null) {
                return new List<Entity>();
            }

            List<Entity> entitiesToRemove = new List<Entity>();
            foreach (Entity entity in list) {
                if (!(entity is Typedef || entity is Struct)) {
                    entitiesToRemove.Add(entity);
                }
            }

            entitiesToRemove.ForEach(item => list.Remove(item));
            return list;
        }

        public static string GetTypeQualifiedId(this Expression expression) {
            if (expression is IdentifierExpression) {
                string identifier = ((IdentifierExpression)expression).Identifier;
                bool dummyBool;
                float dummyFloat;
                int dummyInt;
                if (identifier == "null") {
                    return "null";
                } else if (bool.TryParse(identifier, out dummyBool)) {
                    return "bool";
                } else if (identifier.StartsWith("\"") && identifier.EndsWith("\"")) {
                    return "string";
                } else if (float.TryParse(identifier, out dummyFloat)) {
                    return "fixed";
                } else if (int.TryParse(identifier, out dummyInt)) {
                    return "int";
                }

                IList<Entity> list = new List<Entity>(ScopeEntityFilterer.FilterEntities(NamedEntityRegistre.GetEntitiesWithName(identifier), expression));
                string ambiguityEntities;
                if (list.IsAmbiguous(out ambiguityEntities)) {
                    ErrorSink.AddError(ErrorSink.Error.Create("Ambiguity between entities " + ambiguityEntities, expression));
                    return "";
                }

                if (list.Count > 0) {
                    Entity entity = list[0];
                    if (entity is Function) {
                        return ((Function)entity).Type.GetQualifiedId();
                    } else if (entity is Variable) {
                        return ((Variable)entity).Type.GetQualifiedId();
                    } else if (entity is Struct) {
                        return ((Struct)entity).Name;
                    } else if (entity is Typedef) {
                        return ((Typedef)entity).CreatedType.GetQualifiedId();
                    }
                }
            } else if (expression is ValueExpression) {
                ValueExpression valueExpression = expression as ValueExpression;
                switch (valueExpression.Type) {
                    case ValueExpression.ExpressionType.FloatLiteral:
                        return "fixed";
                    case ValueExpression.ExpressionType.DecLiteral:
                    case ValueExpression.ExpressionType.HexLiteral:
                    case ValueExpression.ExpressionType.OctLiteral:
                        return "int";
                    case ValueExpression.ExpressionType.StringLiteral:
                        return "string";
                    case ValueExpression.ExpressionType.ExpressionEncapsulation:
                        return valueExpression.ChildExpression.GetTypeQualifiedId();
                    case ValueExpression.ExpressionType.MemberAccess:
                        return valueExpression.Value.GetTypeQualifiedId();
                }
            } else if (expression is MemberAccessExpression) {
                MemberAccessExpression memberAccessExpression = expression as MemberAccessExpression;
                List<Entity> list = new List<Entity>(memberAccessExpression.GetReferencedEntities());
                if (list == null || list.Count == 0) {
                    ErrorSink.AddError(ErrorSink.Error.Create("Cannot find entity '" + memberAccessExpression.GetQualifiedId() + "'", memberAccessExpression));
                }

                string ambiguityEntities;
                if (list.IsAmbiguous(out ambiguityEntities)) {
                    ErrorSink.AddError(ErrorSink.Error.Create("Ambiguity between entities " + ambiguityEntities, memberAccessExpression));
                }

                switch (memberAccessExpression.Type) {
                    case MemberAccessExpression.ExpressionType.ArrayAccess:
                    case MemberAccessExpression.ExpressionType.VariableAccess:
                        Variable variable = null;
                        foreach (Entity entity in list) {
                            if (entity is Variable) {
                                variable = entity as Variable;
                                break;
                            }
                        }

                        if (variable != null) {
                            string qualifiedId = variable.Type.GetQualifiedId();
                            if (qualifiedId.EndsWith("]")) {
                                qualifiedId = qualifiedId.Substring(0, qualifiedId.IndexOf("["));
                            }

                            return qualifiedId;
                        }

                        break;
                    case MemberAccessExpression.ExpressionType.FunctionCall:
                        Function function = null;
                        foreach (Entity entity in list) {
                            if (entity is Function) {
                                function = entity as Function;
                                break;
                            }
                        }

                        if (function != null) {
                            return function.Type.GetQualifiedId();
                        }

                        break;
                }
            } else if (expression is UnaryExpression) {
                return ((UnaryExpression)expression).Value.GetTypeQualifiedId();
            } else if (expression is PointerExpression) {
                PointerExpression pointerExpression = expression as PointerExpression;
                string leftType = pointerExpression.Left.GetTypeQualifiedId();
                string rightType = pointerExpression.Right.GetQualifiedId();
                IList<Entity> structs = new List<Entity>(ScopeEntityFilterer.FilterEntities(NamedEntityRegistre.GetEntitiesWithName(leftType), expression));
                string ambiguityEntities;
                if (structs.IsAmbiguous(out ambiguityEntities)) {
                    ErrorSink.AddError(ErrorSink.Error.Create("Ambiguity between entities " + ambiguityEntities, pointerExpression));
                }

                Struct s = structs.Count > 0 ? structs[0] as Struct : null;
                if (s != null) {
                    IEnumerable<Entity> list = NamedEntityRegistre.GetEntitiesWithName(rightType);
                    if (list != null) {
                        foreach (Entity entity in list) {
                            if (entity.Parent == s) {
                                if (entity is Function) {
                                    return ((Function)entity).Type.GetQualifiedId();
                                } else if (entity is Variable) {
                                    return ((Variable)entity).Type.GetQualifiedId();
                                } else if (entity is Struct) {
                                    return ((Struct)entity).Name;
                                } else if (entity is Typedef) {
                                    return ((Typedef)entity).CreatedType.GetQualifiedId();
                                }
                            }
                        }

                        ErrorSink.AddError(ErrorSink.Error.Create("Cannot find member '" + rightType + "' in type '" + s.Name + "'", expression));
                    }
                } else {
                    ErrorSink.AddError(ErrorSink.Error.Create("Cannot find type '" + leftType + "'", expression));
                }
            } else if (expression is CompareExpression || expression is EquateExpression) {
                return DefaultTypeReferences.Bool.GetQualifiedId();
            } else if (expression is ShiftExpression) {
                return DefaultTypeReferences.Int.GetQualifiedId();
            } else if (expression is ConditionExpression) {
                ConditionExpression conditionExpression = expression as ConditionExpression;
                if (conditionExpression.Type == ConditionExpression.ExpressionType.And || conditionExpression.Type == ConditionExpression.ExpressionType.Or) {
                    return DefaultTypeReferences.Bool.GetQualifiedId();
                }

                return DefaultTypeReferences.Int.GetQualifiedId();
            } else if (expression is AddExpression) {
                AddExpression addExpression = expression as AddExpression;
                string leftType = addExpression.Left.GetTypeQualifiedId();
                string rightType = addExpression.Right.GetTypeQualifiedId();
                if (leftType == rightType) {
                    return leftType;
                }
            } else if (expression is MultiplyExpression) {
                MultiplyExpression multiplyExpression = expression as MultiplyExpression;
                string leftType = multiplyExpression.Left.GetTypeQualifiedId();
                string rightType = multiplyExpression.Right.GetTypeQualifiedId();
                if (leftType == rightType) {
                    return leftType;
                }
            } else if (expression is AssignExpression) {
                AssignExpression assignExpression = expression as AssignExpression;
                string leftType = assignExpression.Left.GetTypeQualifiedId();
                string rightType = assignExpression.Right.GetTypeQualifiedId();
                if (leftType == rightType) {
                    return leftType;
                }
            }

            return "";
        }

        public static bool IsAmbiguous(this IList<Entity> list, out string ambiguityEntities) {
            return IsAmbiguous(list, out ambiguityEntities, false);
        }

        public static bool IsAmbiguous(this IList<Entity> list, out string ambiguityEntities, bool typesOnly) {
            ambiguityEntities = "";
            if (list.Count > 1) {
                int index = 0;
                foreach (Entity entity in list) {
                    if (typesOnly && !(entity is Struct || entity is Typedef)) {
                        continue;
                    }

                    ambiguityEntities += "'" + entity.GetPotentialName() + "'";
                    if (!(index == list.Count - 1)) {
                        ambiguityEntities += ", ";
                    }

                    index++;
                }

                if (index != 1) {
                    return true;
                }
            }

            return false;
        }

        public static string GetTypeQualifiedId(this TypeReference typeReference) {
            return typeReference.Type.GetQualifiedId();
        }

        public static string GetQualifiedId(this Expression expression) {
            if (expression is IdentifierExpression) {
                return ((IdentifierExpression)expression).Identifier;
            } else if (expression is ValueExpression) {
                ValueExpression valueExpression = expression as ValueExpression;
                switch (valueExpression.Type) {
                    case ValueExpression.ExpressionType.DecLiteral:
                    case ValueExpression.ExpressionType.FloatLiteral:
                    case ValueExpression.ExpressionType.HexLiteral:
                    case ValueExpression.ExpressionType.OctLiteral:
                    case ValueExpression.ExpressionType.StringLiteral:
                        return valueExpression.Value.GetQualifiedId();
                    case ValueExpression.ExpressionType.ExpressionEncapsulation:
                        return valueExpression.ChildExpression.GetQualifiedId();
                    case ValueExpression.ExpressionType.MemberAccess:
                        return valueExpression.Value.GetQualifiedId();
                }
            } else if (expression is MemberAccessExpression) {
                MemberAccessExpression memberAccessExpression = expression as MemberAccessExpression;
                switch (memberAccessExpression.Type) {
                    case MemberAccessExpression.ExpressionType.FunctionCall:
                    case MemberAccessExpression.ExpressionType.ArrayAccess:
                    case MemberAccessExpression.ExpressionType.VariableAccess:
                        return memberAccessExpression.Member.GetQualifiedId();
                }
            } else if (expression is UnaryExpression) {
                return ((UnaryExpression)expression).Value.GetQualifiedId();
            } else if (expression is PointerExpression) {
                PointerExpression pointerExpression = expression as PointerExpression;
                return pointerExpression.Left.GetQualifiedId() + "." + pointerExpression.Right.GetQualifiedId();
            }

            return "";
        }

        public static string GetQualifiedId(this TypeReference typeReference) {
            string qualifiedId = typeReference.Type.GetQualifiedId();
            return qualifiedId;
        }

        public static bool IsDefaultType(this Expression expression) {
            if (expression.GetQualifiedId() == "null") {
                return true;
            }

            string typeId = expression.GetTypeQualifiedId();
            FieldInfo[] fields = typeof(DefaultTypeReferences).GetFields();
            foreach (FieldInfo field in fields) {
                if (field.FieldType == typeof(TypeReference)) {
                    bool value = typeId == (field.GetValue(null) as TypeReference).GetQualifiedId() || (new TypeReference(new IdentifierExpression((field.GetValue(null) as TypeReference).GetQualifiedId())).DoesTypeReferenceResolveToTypedefCreatedType(typeId));
                    if (value) {
                        return true;
                    }
                }
            }

            return false;
        }
    }
}
